﻿using System;
using System.Windows;
using nRoute.Components;
using nRoute.Components.Composition;
using nRoute.Components.Messaging;
#if WP7 && NFRAMEWORK
using nRoute.Navigation;
using System.Windows.Threading;
using nRoute.Components;
#endif
#if (WINRT)
using System.Threading.Tasks;
using Windows.UI.Xaml;
using nRoute.Navigation;
using Windows.ApplicationModel.Core;
using nRoute.Components.Routing;
using Windows.System.Threading;
#endif

namespace nRoute.ApplicationServices2
{
    public partial class nRouteApplicationService      
        : IApplicationService, IApplicationLifetimeAware
    {
        private const string APPSERVICE_ALREADY_INIT = "nRoute Application Service is already initialized";
        private const string TOMBSTONE_STATE_KEY = "nRoute.TombstoneState";

        private readonly static Object _lock = new Object();

        private static nRouteApplicationService _instance;
        private static ApplicationState _state;
        private static bool _isInitialized;
        private static IResourceCatalog _resourceCatalog;

        public event EventHandler Initialized;

        public nRouteApplicationService()
        {
            if (_instance == null) _instance = this;
            _resourceCatalog = new ResourceCatalog();

#if (WINRT)
            // need to double check this doesn't leak mem
            CoreApplication.Exiting += Application_Exiting;
            CoreApplication.Resuming += Application_Resuming;
            CoreApplication.Suspending += Application_Suspending;
#elif (WP7)
            base.Launching += nRouteApplicationService_Launching;
            base.Closing += nRouteApplicationService_Closing;
            base.Activated += nRouteApplicationService_Activated;
            base.Deactivated += nRouteApplicationService_Deactivated;
#endif
        }

#region Properties

        public static nRouteApplicationService Current
        {
            get { return _instance; }
        }

        public IResourceCatalog ResourceCatalog
        {
            get { return _resourceCatalog; }
        }

        public static bool IsInitialized
        {
            get
            {
                lock (_lock)
                {
                    return _isInitialized;
                }
            }
        }

        public static ApplicationState CurrentApplicationState
        {
            get
            {
                lock (_lock)
                {
                    return _state;
                }
            }
        }

#endregion

#region IApplicationService Members

        public new void StartService(ApplicationServiceContext context)
        {
            if (!IsInitialized)
            {
#if (WINRT)
                // make the parent most task run synchronously - this ensures the resources are available on demand
                Initialize().ContinueWith((t) =>
                {
                    if (this.Initialized != null) this.Initialized(this, EventArgs.Empty);
                }, TaskContinuationOptions.ExecuteSynchronously);
#else 
                Initialize();
                if (this.Initialized != null) this.Initialized(this, EventArgs.Empty);
#endif
            }

#if (WP7)
			base.StartService(context);
#endif
        }

        public new void StopService()
        {
            // do nothing
#if (WP7)
			base.StopService();
#endif
        }

#endregion

#region IApplicationLifetimeAware Members

        public void Exited()
        {
            PublishApplicationState(ApplicationState.Exited);
        }

        public void Exiting()
        {
            PublishApplicationState(ApplicationState.Exiting);
        }

        public void Started()
        {
            PublishApplicationState(ApplicationState.Started);
        }

        public void Starting()
        {
            PublishApplicationState(ApplicationState.Starting);
        }

#if (WP7 || WINRT)

		private new void Launching()
		{
			PublishApplicationState(ApplicationState.Launching);
		}

		private new void Closing()
		{
			PublishApplicationState(ApplicationState.Closing);
		}

		private new void Activated()
		{
#if NFRAMEWORK
            var timer = new DispatcherTimer { Interval= TimeSpan.FromMilliseconds(10) };
            timer.Tick += (s, e) =>
            {
                if (Application.Current.RootVisual == null)
                {
                    return;
                }

                timer.Stop();

                var applicationFrame = Application.Current.RootVisual as ISupportNavigationViewState;
                if (applicationFrame != null)
                {
                    applicationFrame.RestoreState((ParametersCollection)State[TOMBSTONE_STATE_KEY]);
                    State[TOMBSTONE_STATE_KEY] = null;
                }
            };
            timer.Start();
#endif
			PublishApplicationState(ApplicationState.Activated);
			
		}

		private new void Deactivated()
		{
#if NFRAMEWORK
            var applicationFrame = Application.Current.RootVisual as ISupportNavigationViewState;
            if (applicationFrame != null)
            {
                base.State[TOMBSTONE_STATE_KEY] = applicationFrame.SaveState();
            }
#endif
		    PublishApplicationState(ApplicationState.Deactivated);
		}

#endif

#endregion

#region Helpers

#if (WINRT)
        private static async Task Initialize()
        {
            // we check
            if (_isInitialized)
            {
                throw new InvalidOperationException(APPSERVICE_ALREADY_INIT);
            }

            lock (_lock)
            {
                // double check and set 
                if (_isInitialized) return;
                _isInitialized = true;
            }

            // initialize the basic stuff
            //await nRoute.Components.Composition.Resource.Initialize().ContinueWith((t) =>
            //{

            // TEMP
            var _catalog = (ResourceCatalog)_resourceCatalog;
            var _x = Task.Factory.StartNew(() =>
            { 
                
                nRoute.Navigation.NavigationService.Initialize(_catalog.TypeBuilder);
                
            });
            _x.Start();

            //var _token = default(IDisposable);
            //_token = _catalog.GetCatalogPublisher(typeof(IRouteHandler)).Subscribe((c) => 
            //{
            //    _token.Dispose();
            //});
#if (!TODO)
                nRoute.Controllers.ControllerService.Initialize();
                nRoute.SiteMaps.SiteMapService.Initialize();
#endif
            //});
        }
#else
        private static void Initialize()
        {
            // we check
            if (_isInitialized)
            {
                throw new InvalidOperationException(APPSERVICE_ALREADY_INIT);
            }

            lock (_lock)
            {
                // double check
                if (_isInitialized) return;

                // initialize the basic stuff
                //nRoute.Components.Composition.Resource.Initialize();
                nRoute.Navigation.NavigationService.Initialize(((ResourceCatalog)_resourceCatalog).TypeBuilder);
                nRoute.Controllers.ControllerService.Initialize(((ResourceCatalog)_resourceCatalog).TypeBuilder);
                nRoute.SiteMaps.SiteMapService.Initialize();

                // and set 
                _isInitialized = true;
            }
        }
#endif

        private static void PublishApplicationState(ApplicationState state)
        {
            lock (_lock)
            {
                _state = state;
                Channel.Publish<ApplicationStateInfo>(new ApplicationStateInfo(state));
            }
        }

#endregion

    }
}